package local;

import model.Game;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * User: gutnikov
 * Date: 06.09.2010
 */

public class GameGrabber {

	private static String FILES_ROOT = "./games";

	private static Pattern gameLink = Pattern.compile("<a href=\"(.*)\" class=\"play_link\">.*</a>");
	private static Pattern gameName = Pattern.compile(".*/(.*)");
	private static Pattern iconLink = Pattern.compile("<img.*class=\"game_icon\".* src=\"(.+.(png|jpg)).+\" title=.*/>");
	private static Pattern playsNum = Pattern.compile("<a.*>(.*)&nbsp;plays</a>");
	private static Pattern devBy = Pattern.compile("<dd class=\"developer\">by.*<a.*>(.*)</a></dd>");
	private static Pattern rating = Pattern.compile("<li class=\"current-rating spritegame spriteall\".*>Currently (.*)/5 Stars.*</li>");
	private static Pattern swfUrl1 = Pattern.compile("\"game_swf\":\"(.+?.swf).*\",\"");
	private static Pattern swfUrl2 = Pattern.compile("embedSWF\\(\"(http://chat\\.kongregate\\.com/gamez.+?\\.swf).*\"");	
	private static Pattern nextPage = Pattern.compile("<li class=\"next\"><a href=\".*pdis=(.*)\">");
	private static Pattern descr = Pattern.compile("<span class=\"summary\">(.*?)</span>", Pattern.DOTALL );


	private static PreparedStatement st;

	public static void main(String[] args) throws Exception {
		// preparing database
		Class.forName("org.sqlite.JDBC");
		Connection conn = DriverManager.getConnection("jdbc:sqlite:/home/alexander/work/kong/gtube-portal/games.db");
		st = conn.prepareStatement("insert into games(name,source_url,raw_path,swf_path,rating,icon_path,author,plays,genre,description) values(?,?,?,?,?,?,?,?,?,?)");

		GameGrabber gg = new GameGrabber();

		gg.grabChainedPages("http://www.kongregate.com/strategy-defense-games", "strategy-defense", 1);

		//gg.grabchainedpages("http://www.kongregate.com/action-games","action",1);
		//gg.grabchainedpages("http://www.kongregate.com/multiplayer-games","multiplayer",1);
		//gg.grabchainedpages("http://www.kongregate.com/shooter-games","shooter",1);

	}

	private void grabChainedPages(String urlstr,String genre, int depth){
	String postfix = "";
	for(int i = 0; i < depth; i++){
		try {
			System.out.println("grabbing " + urlstr + postfix);
			String in = load(new URL(urlstr + postfix));
			grabGamePage(in,genre);
			String nextHref = findMatches(in,nextPage).get(0);
			if(nextHref == null)
				break;
			postfix = "?pdis=" + nextHref;
		} catch (Exception e){
			System.out.println("Error grabbing page " + urlstr + postfix + ":" + e);
		}
	}
	}

	private void grabGamePage(String page,String genre){	
	List<String> links = findMatches(page,gameLink);
	List<String> icons = findMatches(page,iconLink);
	List<String> plays = findMatches(page,playsNum);
	List<String> auths = findMatches(page,devBy);
	List<String> rates = findMatches(page,rating);

	int count = links.size();
	if(icons.size() != count || plays.size() != count || auths.size() != count || rates.size() != count)
		throw new IllegalStateException("Missing data");

	for (int i = 0; i < links.size(); i++) {
		try {
			System.out.println("grabbing " + links.get(i) + " page");
			String[] swfurlAndDescr = getSwfUrlAndDescr(links.get(i));
			Game g = createGameRecord(links.get(i), swfurlAndDescr[0], icons.get(i), plays.get(i), auths.get(i), rates.get(i), genre, swfurlAndDescr[1]);


			// sql here
			saveToDb( g );

			if (g.getRawPath() != null)
				saveToFile(page, g.getRawPath());
			else throw new IllegalStateException("Raw path is null");

			if (g.getSwfPath() != null)
				saveToFile(new URL(swfurlAndDescr[0]), g.getSwfPath());
            else throw new IllegalStateException("Swf path is null");

			saveToFile(new URL(icons.get(i)), g.getIconPath());

		} catch (Exception e) {
			System.out.println("Error saving game: " + e);
		}
	}
	}

 	// save to sqlite
	private void saveToDb( Game g ) throws SQLException {

		st.setString(1,g.getName());
		st.setString(2,g.getSourceUrl());
		st.setString(3,g.getRawPath());
		st.setString(4,g.getSwfPath());
		st.setFloat(5, g.getRating());
		st.setString(6,g.getIconPath());
		st.setString(7,g.getAuthor());
		st.setLong(8, g.getPlays());
		st.setString(9,g.getGenre());
		st.setString(10,g.getDescription());

		st.execute();
	}


	private static Game createGameRecord(String url, String swfurl, String icon, String plays, String author, String rating, String genre, String descr){
	Game g = new Game();
	g.setSourceUrl(url);
	String name = getLastUrlElement(url);
	g.setName(name);
	g.setRawPath(FILES_ROOT + "/" + name + "/raw.html");
	String swfname = getLastUrlElement(swfurl);
	g.setSwfPath(FILES_ROOT + "/" + name + "/" + swfname);
	String iconname = getLastUrlElement(icon);
	g.setIconPath(FILES_ROOT + "/" + name + "/" + iconname);
	g.setPlays(new Long(plays.replaceAll(",","")));
	g.setAuthor(author);
	g.setRating(new Float(rating));
	g.setGenre(genre);
	g.setDescription( descr );
	return g;
	}

	private static String getLastUrlElement(String url){
	List<String> els = findMatches(url,gameName);
	return els.size() > 0 ? els.get(0) : null;
	}

	private static List<String> findMatches(String in, Pattern p){
	List<String> r = new ArrayList<String>(20);
	Matcher m = p.matcher(in);
	while(m.find()){
		try {
			r.add(URLDecoder.decode(m.group(1),"utf-8"));
		} catch (UnsupportedEncodingException e) {}
	}
	return r;
	}

	private static String[] getSwfUrlAndDescr(String urlstr) throws MalformedURLException, UnsupportedEncodingException {
	URL url = new URL(urlstr);
	String gamePage = load(url);
	Matcher m1 = swfUrl1.matcher(gamePage), m2 = swfUrl2.matcher(gamePage);
	String swfurl = null;
	if(m1.find())
		swfurl = m1.group(1);
	else if(m2.find())
		swfurl = m2.group(1);

	// get description
	Matcher dm = descr.matcher( gamePage );
	String dsc = null;
	if( dm.find() ){
		dsc = dm.group(1);
	}
	return new String[]{swfurl != null ? URLDecoder.decode(swfurl,"utf-8") : null,dsc};
	}

	public static void saveToFile(URL url, String fpath) throws IOException {
	saveToFile(url.openStream(),fpath);
	}

	public static void saveToFile(String in, String fpath) throws IOException{
	saveToFile(new ByteArrayInputStream(in.getBytes("utf-8")),fpath);
	}

	public static void saveToFile(InputStream in, String fpath) throws IOException {
	File f = new File(fpath);
    if(!f.exists()){
        File p = new File(f.getParent());
        if(!p.exists())
            p.mkdirs();
        f.createNewFile();
    }

	OutputStream fos = new FileOutputStream(f);
	byte[] arr = new byte[2048];
	int n = 0;
	while((n = in.read(arr)) != -1){
		fos.write(arr,0,n);
	}
	fos.close();
	in.close();
	}
	
	public static String load(URL url){
	StringBuilder sb = new StringBuilder();
	try {
		InputStreamReader in = new InputStreamReader(new BufferedInputStream(url.openStream()));
		char[] buf = new char[2048];
		int n = 0;
		while((n = in.read(buf)) != -1){
			sb.append(buf,0,n);
		}
	} catch (IOException e) {
		System.out.println(e);
	}
	return sb.toString();
	}

	static String s ="<span class=\"summary\">\n" +
			"            <p>Protect your gems from being stolen by “good” heroes in this tower defense game. Overlord, you have all the power of orcs, undead and demons.</p>\n" +
			"            </span>	other </span>" ;
	public static void main1(String[] args) {

		Matcher m = Pattern.compile("<span class=\"summary\">(.*?)</span>", Pattern.DOTALL ).matcher(s);

		boolean b = m.find();

		if( b ){
			String r = m.group(1);
			System.out.println( r );
		}

		int a= 10;
	}

}
